package org.xxpay.pay.channel.alizftpay;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.*;
import com.alipay.api.domain.*;
import com.alipay.api.request.AlipayTradeAppPayRequest;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.request.AlipayTradeWapPayRequest;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.alipay.api.response.AlipayTradeWapPayResponse;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.xxpay.apibase.constant.ABCS;
import org.xxpay.apibase.service.IAPIOrderService;
import org.xxpay.apibase.service.IAPISysConfigService;
import org.xxpay.apibase.service.IDCAlizftpayChannelService;
import org.xxpay.apibase.service.IDCPaymentService;
import org.xxpay.apibase.util.AmountKit;
import org.xxpay.apibase.util.Base64Kit;
import org.xxpay.apibase.vo.ApiPayOrder;
import org.xxpay.apibase.vo.api.AbstractRes;
import org.xxpay.apibase.vo.api.ApiBuilder;
import org.xxpay.apibase.vo.api.PayRes;
import org.xxpay.apibase.vo.api.msg.QueryRetMsg;

import java.io.File;
import java.net.URLEncoder;
import java.util.Arrays;

/**
* @Description: 支付宝直付通
* @author xxpay
*/
@Service
public class AlizftpayPaymentService implements IDCPaymentService {

    private static final Logger logger = LoggerFactory.getLogger(AlizftpayPaymentService.class);

    //注入订单更新函数
    @Autowired private IAPIOrderService apiOrderService;

    @Autowired private IAPISysConfigService sysConfigService;

    @Autowired private IDCAlizftpayChannelService alizftpayChannelService;

    @Override
    public String regenPayOrderId(ApiPayOrder apiPayOrder, JSONObject payParamJSON) {
        return null;
    }

    @Override
    public Long recalculatePayOrderAmount(ApiPayOrder apiPayOrder, JSONObject payParamJSON) {
        return null;
    }

    @Override
    public AbstractRes pay(ApiPayOrder apiPayOrder, JSONObject payParamJSON, JSONObject sysConfigJSON) {

        String channelId = apiPayOrder.getChannelId();
        AbstractRes retObj;
        switch (channelId) {
            case AlizftpayConfig.PAY_CHANNEL_WAP :
                retObj = doWap(apiPayOrder, payParamJSON, sysConfigJSON);  //TODO 正常
                break;
            case AlizftpayConfig.PAY_CHANNEL_PC :
                retObj = doPC(apiPayOrder, payParamJSON, sysConfigJSON); //TODO 未找到对应接口
                break;
            case AlizftpayConfig.PAY_CHANNEL_APP :
                retObj = doAPP(apiPayOrder, payParamJSON, sysConfigJSON);   //TODO 可调起app,提示协议过期，未走完流程
                break;
            case AlizftpayConfig.PAY_CHANNEL_QR :
                retObj = doJSAPI(apiPayOrder, payParamJSON, sysConfigJSON);  //TODO 正常
                break;
            default:
                retObj = ApiBuilder.bizError("不支持的支付宝渠道[channelId="+channelId+"]");
                break;
        }
        return retObj;
    }


    public AbstractRes doWap(ApiPayOrder apiPayOrder, JSONObject payParamJSON, JSONObject sysConfigJSON) {

        // ↓↓ 以下为订单常用数据， 其他请查看 ApiPayOrder 属性 ↓↓
        String payOrderId = apiPayOrder.getPayOrderId();    //生成的系统支付订单号
        Long amount = apiPayOrder.getAmount();              //接口上送参数： 下单金额： 单位分
        String clientIP = apiPayOrder.getClientIp();        //接口上送参数： 客户端IP
        String device = apiPayOrder.getDevice();            //接口上送参数： 设备信息
        String subject = apiPayOrder.getSubject();          //接口上送参数： 商品标题
        String body = apiPayOrder.getBody();                //接口上送参数： 商品描述信息
        String extra = apiPayOrder.getExtra();              //接口上送参数： 额外参数
        String channelUser = apiPayOrder.getChannelUser();  //接口上送参数： 渠道用户标识， 如openId 支付宝账号等
        // ↑↑  ↑↑

        //
        String channelId = apiPayOrder.getChannelId();        //渠道编码， 可根据此处理不同的支付场景。  比如： alipay_h5， alipay_pc

        //系统配置参数
        String paySiteUrl = sysConfigJSON.getString("paySiteUrl"); //当前支付系统url， 如：http://pay.alipay.com
        String notifyUrl = sysConfigJSON.getString("notifyUrl"); //异步回调通知地址
        String returnUrl = sysConfigJSON.getString("returnUrl"); //同步跳转地址

        String certRootPath = sysConfigJSON.getString("certRootPath"); //存放证书的根目录

        //封装请求参数

        AlizftpayConfig alizftpayConfig = new AlizftpayConfig(payParamJSON);
        alizftpayConfig.setSysCertRootPath(certRootPath);

        AlipayTradeWapPayRequest alipayRequest = new AlipayTradeWapPayRequest();
        AlipayTradeWapPayModel model = new AlipayTradeWapPayModel();
        model.setOutTradeNo(payOrderId);
        model.setSubject(apiPayOrder.getSubject());
        model.setTotalAmount(AmountKit.convertCent2Dollar(apiPayOrder.getAmount().toString()));
        model.setBody(apiPayOrder.getBody());
        model.setProductCode("QUICK_WAP_PAY");
        // 获取objParams参数
        String objParams = apiPayOrder.getExtra();
        if (StringUtils.isNotEmpty(objParams)) {
            try {
                JSONObject objParamsJson = JSON.parseObject(objParams);
                if (StringUtils.isNotBlank(objParamsJson.getString("quit_url"))) {
                    model.setQuitUrl(objParamsJson.getString("quit_url"));
                }
            } catch (Exception e) {
                logger.error("{}objParams参数格式错误！");
            }

        }

        //传入二级商户ID
        SubMerchant subMerchant = new SubMerchant();
        subMerchant.setMerchantId(apiPayOrder.getChannelSMId());   //进件的SMID
        model.setSubMerchant(subMerchant);

        //传入结算信息
        SettleInfo settleInfo = new SettleInfo();
        SettleDetailInfo settleDetailInfo = new SettleDetailInfo();
        settleDetailInfo.setAmount(model.getTotalAmount());  //全部金额
        settleDetailInfo.setTransInType("defaultSettle");  //进件默认分账用户
        settleInfo.setSettleDetailInfos(Arrays.asList(settleDetailInfo));
        model.setSettleInfo(settleInfo);

        alipayRequest.setBizModel(model);

        // 设置异步通知地址
        alipayRequest.setNotifyUrl(notifyUrl);
        // 设置同步跳转地址
        alipayRequest.setReturnUrl(returnUrl);

        try {
            AlipayTradeWapPayResponse response = getAlipayClient(alizftpayConfig).pageExecute(alipayRequest);

            if(! response.isSuccess()){

                logger.error("调起支付宝直付通返回失败！, resp: {}", response);
                return ApiBuilder.bizError("下单失败[" + response.getMsg() + "]");
            }


            String jumpInfo = response.getBody();

            if(StringUtils.isEmpty(jumpInfo)){
                return ApiBuilder.bizError("调用支付宝异常!");
            }

            //上游订单号
            String channelPayOrderId = response.getTradeNo();

            //更新为支付中
            apiOrderService.updateOrderReady2Ing(payOrderId, channelPayOrderId);

            //返回构造数据
            PayRes payRes = ApiBuilder.buildSuccess(PayRes.class);
            payRes.setJumpInfo(jumpInfo);
            return payRes;

        } catch (AlipayApiException e) {
            logger.error("", e);
            return ApiBuilder.bizError("下单失败[" + e.getErrMsg() + "]");
        } catch (Exception e) {
            logger.error("", e);
            return ApiBuilder.bizError("下单失败[调取通道异常]");
        }

    }

    public AbstractRes doPC(ApiPayOrder apiPayOrder, JSONObject payParamJSON, JSONObject sysConfigJSON) {

        // ↓↓ 以下为订单常用数据， 其他请查看 ApiPayOrder 属性 ↓↓
        String payOrderId = apiPayOrder.getPayOrderId();    //生成的系统支付订单号
        Long amount = apiPayOrder.getAmount();              //接口上送参数： 下单金额： 单位分
        String clientIP = apiPayOrder.getClientIp();        //接口上送参数： 客户端IP
        String device = apiPayOrder.getDevice();            //接口上送参数： 设备信息
        String subject = apiPayOrder.getSubject();          //接口上送参数： 商品标题
        String body = apiPayOrder.getBody();                //接口上送参数： 商品描述信息
        String extra = apiPayOrder.getExtra();              //接口上送参数： 额外参数
        String channelUser = apiPayOrder.getChannelUser();  //接口上送参数： 渠道用户标识， 如openId 支付宝账号等
        // ↑↑  ↑↑

        //
        String channelId = apiPayOrder.getChannelId();        //渠道编码， 可根据此处理不同的支付场景。  比如： alipay_h5， alipay_pc

        //系统配置参数
        String paySiteUrl = sysConfigJSON.getString("paySiteUrl"); //当前支付系统url， 如：http://pay.alipay.com
        String notifyUrl = sysConfigJSON.getString("notifyUrl"); //异步回调通知地址
        String returnUrl = sysConfigJSON.getString("returnUrl"); //同步跳转地址

        String certRootPath = sysConfigJSON.getString("certRootPath"); //存放证书的根目录

        //封装请求参数

        AlizftpayConfig alizftpayConfig = new AlizftpayConfig(payParamJSON);
        alizftpayConfig.setSysCertRootPath(certRootPath);

        AlipayTradeWapPayRequest alipayRequest = new AlipayTradeWapPayRequest();
        AlipayTradeWapPayModel model = new AlipayTradeWapPayModel();
        model.setOutTradeNo(payOrderId);
        model.setSubject(apiPayOrder.getSubject());
        model.setTotalAmount(AmountKit.convertCent2Dollar(apiPayOrder.getAmount().toString()));
        model.setBody(apiPayOrder.getBody());
        model.setProductCode("QUICK_WAP_PAY");
        // 获取objParams参数
        String objParams = apiPayOrder.getExtra();
        if (StringUtils.isNotEmpty(objParams)) {
            try {
                JSONObject objParamsJson = JSON.parseObject(objParams);
                if (StringUtils.isNotBlank(objParamsJson.getString("quit_url"))) {
                    model.setQuitUrl(objParamsJson.getString("quit_url"));
                }
            } catch (Exception e) {
                logger.error("{}objParams参数格式错误！");
            }

        }

        //传入二级商户ID
        SubMerchant subMerchant = new SubMerchant();
        subMerchant.setMerchantId(apiPayOrder.getChannelSMId());   //进件的SMID
        model.setSubMerchant(subMerchant);

        //传入结算信息
        SettleInfo settleInfo = new SettleInfo();
        SettleDetailInfo settleDetailInfo = new SettleDetailInfo();
        settleDetailInfo.setAmount(model.getTotalAmount());  //全部金额
        settleDetailInfo.setTransInType("defaultSettle");  //进件默认分账用户
        settleInfo.setSettleDetailInfos(Arrays.asList(settleDetailInfo));
        model.setSettleInfo(settleInfo);

        // 设置异步通知地址
        alipayRequest.setNotifyUrl(notifyUrl);
        // 设置同步跳转地址
        alipayRequest.setReturnUrl(returnUrl);

        try {
            AlipayTradeWapPayResponse response = getAlipayClient(alizftpayConfig).pageExecute(alipayRequest);

            if(! response.isSuccess()){

                logger.error("调起支付宝直付通返回失败！, resp: {}", response);
                return ApiBuilder.bizError("下单失败[" + response.getMsg() + "]");
            }


            String jumpInfo = response.getBody();

            if(StringUtils.isEmpty(jumpInfo)){
                return ApiBuilder.bizError("调用支付宝异常!");
            }

            //上游订单号
            String channelPayOrderId = response.getTradeNo();

            //更新为支付中
            apiOrderService.updateOrderReady2Ing(payOrderId, channelPayOrderId);

            //返回构造数据
            PayRes payRes = ApiBuilder.buildSuccess(PayRes.class);
            payRes.setJumpInfo(jumpInfo);
            return payRes;

        } catch (AlipayApiException e) {
            logger.error("", e);
            return ApiBuilder.bizError("下单失败[" + e.getErrMsg() + "]");
        } catch (Exception e) {
            logger.error("", e);
            return ApiBuilder.bizError("下单失败[调取通道异常]");
        }

    }

    public AbstractRes doAPP(ApiPayOrder apiPayOrder, JSONObject payParamJSON, JSONObject sysConfigJSON) {

        // ↓↓ 以下为订单常用数据， 其他请查看 ApiPayOrder 属性 ↓↓
        String payOrderId = apiPayOrder.getPayOrderId();    //生成的系统支付订单号
        Long amount = apiPayOrder.getAmount();              //接口上送参数： 下单金额： 单位分
        String clientIP = apiPayOrder.getClientIp();        //接口上送参数： 客户端IP
        String device = apiPayOrder.getDevice();            //接口上送参数： 设备信息
        String subject = apiPayOrder.getSubject();          //接口上送参数： 商品标题
        String body = apiPayOrder.getBody();                //接口上送参数： 商品描述信息
        String extra = apiPayOrder.getExtra();              //接口上送参数： 额外参数
        String channelUser = apiPayOrder.getChannelUser();  //接口上送参数： 渠道用户标识， 如openId 支付宝账号等
        // ↑↑  ↑↑

        //
        String channelId = apiPayOrder.getChannelId();        //渠道编码， 可根据此处理不同的支付场景。  比如： alipay_h5， alipay_pc

        //系统配置参数
        String paySiteUrl = sysConfigJSON.getString("paySiteUrl"); //当前支付系统url， 如：http://pay.alipay.com
        String notifyUrl = sysConfigJSON.getString("notifyUrl"); //异步回调通知地址
        String returnUrl = sysConfigJSON.getString("returnUrl"); //同步跳转地址

        String certRootPath = sysConfigJSON.getString("certRootPath"); //存放证书的根目录

        //封装请求参数

        AlizftpayConfig alizftpayConfig = new AlizftpayConfig(payParamJSON);
        alizftpayConfig.setSysCertRootPath(certRootPath);

        AlipayTradeAppPayRequest alipayRequest = new AlipayTradeAppPayRequest();
        AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
        model.setOutTradeNo(payOrderId);
        model.setSubject(apiPayOrder.getSubject());
        model.setTotalAmount(AmountKit.convertCent2Dollar(apiPayOrder.getAmount().toString()));
        model.setBody(apiPayOrder.getBody());
        model.setProductCode("QUICK_MSECURITY_PAY");


        //传入二级商户ID
        SubMerchant subMerchant = new SubMerchant();
        subMerchant.setMerchantId(apiPayOrder.getChannelSMId());   //进件的SMID
        model.setSubMerchant(subMerchant);

        //传入结算信息
        SettleInfo settleInfo = new SettleInfo();
        SettleDetailInfo settleDetailInfo = new SettleDetailInfo();
        settleDetailInfo.setAmount(model.getTotalAmount());  //全部金额
        settleDetailInfo.setTransInType("defaultSettle");  //进件默认分账用户
        settleInfo.setSettleDetailInfos(Arrays.asList(settleDetailInfo));
        model.setSettleInfo(settleInfo);

        alipayRequest.setBizModel(model);

        // 设置异步通知地址
        alipayRequest.setNotifyUrl(notifyUrl);
        // 设置同步跳转地址
        alipayRequest.setReturnUrl(returnUrl);

        try {

            AlipayClient client = getAlipayClient(alizftpayConfig);
            String payParams = client.sdkExecute(alipayRequest).getBody();

            if(StringUtils.isBlank(payParams)) {
                return ApiBuilder.bizError("调用支付宝异常!");
            }

            //更新为支付中
            apiOrderService.updateOrderReady2Ing(payOrderId, null);

            //返回构造数据
            PayRes payRes = ApiBuilder.buildSuccess(PayRes.class);

            payRes.setPayOrderId(payOrderId);
            JSONObject payParamsJSON = new JSONObject();
            payParamsJSON.put("appStr", payParams);
            payRes.setAppInfo(ABCS.PAY_METHOD_ALIPAY_APP, payParamsJSON);
            return payRes;

        } catch (AlipayApiException e) {
            logger.error("", e);
            return ApiBuilder.bizError("下单失败[" + e.getErrMsg() + "]");
        } catch (Exception e) {
            logger.error("", e);
            return ApiBuilder.bizError("下单失败[调取通道异常]");
        }

    }

    public AbstractRes doJSAPI(ApiPayOrder apiPayOrder, JSONObject payParamJSON, JSONObject sysConfigJSON) {
        String logPrefix = "【支付宝直付通当面付下单】";
        String payOrderId = apiPayOrder.getPayOrderId();
        String paySiteUrl = sysConfigJSON.getString("paySiteUrl");
        JSONObject obj = new JSONObject();
        obj.put("payOrderId", payOrderId);
        String param = Base64Kit.encode(obj.toJSONString().getBytes());

        String domainUrl = alizftpayChannelService.getPayDomain();
        if(StringUtils.isBlank(domainUrl)) domainUrl = paySiteUrl;
        logger.info("获取打开支付宝URL:{}", domainUrl);
        String toUrl = domainUrl + "/api/alizftpay/alipay_qr_%s.htm";
        toUrl = String.format(toUrl, param);

        logger.info("[{}]生成支付宝下单URL={}", logPrefix, toUrl);

        String authUrl = paySiteUrl + "/api/auth/alipay";
        toUrl = authUrl + "?returnUrl=" + toUrl;
        String codeImgUrl = paySiteUrl + "/api/qrcode_img_get?url=" + URLEncoder.encode(toUrl) + "&width=200&height=200";
        PayRes retObj = ApiBuilder.buildSuccess(PayRes.class);
        StringBuffer payForm = new StringBuffer();
        String toPayUrl = paySiteUrl + "/api/alipay/pay_wap.htm";
        payForm.append("<form style=\"display: none\" action=\""+toPayUrl+"\" method=\"post\">");
        payForm.append("<input name=\"mchOrderNo\" value=\""+apiPayOrder.getMchOrderNo()+"\" >");
        payForm.append("<input name=\"payOrderId\" value=\""+apiPayOrder.getPayOrderId()+"\" >");
        payForm.append("<input name=\"amount\" value=\""+apiPayOrder.getAmount()+"\" >");
        payForm.append("<input name=\"toUrl\" value=\""+toUrl+"\" >");
        payForm.append("<input name=\"codeImgUrl\" value=\""+codeImgUrl+"\" >");
        payForm.append("<input type=\"submit\" value=\"立即支付\" style=\"display:none\" >");
        payForm.append("</form>");
        payForm.append("<script>document.forms[0].submit();</script>");

        // 存入统一下单地址
        apiOrderService.saveTopayUrl(payOrderId, payForm.toString());

        // 返回统一下单跳转地址
        String payUrl =  paySiteUrl + "/api/pay_"+payOrderId+".htm";

        retObj.setPayOrderId(payOrderId);
        JSONObject payInfo = new JSONObject();
        retObj.setPayUrl(payForm.toString());
        retObj.setPayJumpUrl(payUrl);
        retObj.setPayMethod(ABCS.PAY_METHOD_FORM_JUMP);
        retObj.setPayParams(payInfo);

        logger.info("###### 商户统一下单处理完成 ######");
        return retObj;

    }
    @Override
    public QueryRetMsg query(ApiPayOrder apiPayOrder, JSONObject payParamJSON){

        String payOrderId = apiPayOrder.getPayOrderId();           //系统订单号

        //执行查单操作...
        String logPrefix = "【支付宝直付通订单查询】";
        logger.info("{}开始查询支付宝直付通通道订单,payOrderId={}", logPrefix, payOrderId);
        AlizftpayConfig alizftpayConfig = new AlizftpayConfig(payParamJSON);

        //封装请求参数
        String certRootPath = sysConfigService.querySysConfig("certRootPath");
        alizftpayConfig.setSysCertRootPath(certRootPath);

        AlipayTradeQueryRequest alipayRequest = new AlipayTradeQueryRequest();
        // 商户订单号，商户网站订单系统中唯一订单号，必填
        AlipayTradeQueryModel model = new AlipayTradeQueryModel();
        model.setOutTradeNo(payOrderId);
        alipayRequest.setBizModel(model);

        AlipayTradeQueryResponse alipayResponse;
        String result = "";
        String channelOrderNo = null;
        try {
            alipayResponse = this.alipayExecute(alizftpayConfig, alipayRequest);
            // 交易状态：
            // WAIT_BUYER_PAY（交易创建，等待买家付款）、
            // TRADE_CLOSED（未付款交易超时关闭，或支付完成后全额退款）、
            // TRADE_SUCCESS（交易支付成功）、
            // TRADE_FINISHED（交易结束，不可退款）
            result = alipayResponse.getTradeStatus();
            channelOrderNo = alipayResponse.getTradeNo();
            logger.info("{}payOrderId={}返回结果:{}", logPrefix, payOrderId, result);

        } catch (AlipayApiException e) {
            logger.error("", e);
        }

        if("TRADE_SUCCESS".equals(result)) {
            return QueryRetMsg.confirmSuccess(channelOrderNo);  //支付成功
        }else if("WAIT_BUYER_PAY".equals(result)) {
            return QueryRetMsg.waiting(); //支付中
        }
        return QueryRetMsg.waiting(); //支付中

    }


    /** 获取支付宝接口调用类 **/
    private DefaultAlipayClient getAlipayClient(AlizftpayConfig alizftpayConfig) throws AlipayApiException {

        if("cert".equals(alizftpayConfig.getEncryptionType())){ //证书加密方式
            CertAlipayRequest certAlipayRequest = new CertAlipayRequest();
            certAlipayRequest.setServerUrl(AlizftpayConfig.ALIPAY_GATEWAY_URL);
            certAlipayRequest.setAppId(alizftpayConfig.getAppId());
            certAlipayRequest.setFormat(AlizftpayConfig.FORMAT);
            certAlipayRequest.setCharset(AlizftpayConfig.CHARSET);

            certAlipayRequest.setSignType(AlizftpayConfig.SIGNTYPE);
            certAlipayRequest.setPrivateKey(alizftpayConfig.getPrivateKey());  //无论 签名 和证书 哪种方式  privateKey 必填！！


            certAlipayRequest.setCertPath(alizftpayConfig.getSysCertRootPath() + File.separator + alizftpayConfig.getAppPublicCert());
            certAlipayRequest.setAlipayPublicCertPath(alizftpayConfig.getSysCertRootPath() + File.separator + alizftpayConfig.getAlipayPublicCert());
            certAlipayRequest.setRootCertPath(alizftpayConfig.getSysCertRootPath() + File.separator + alizftpayConfig.getAlipayRootCert());
            return new DefaultAlipayClient(certAlipayRequest);

        }else{ //key 或者 空都为默认普通加密方式

            return new DefaultAlipayClient(AlizftpayConfig.ALIPAY_GATEWAY_URL, alizftpayConfig.getAppId(),
                    alizftpayConfig.getPrivateKey(), AlizftpayConfig.FORMAT, AlizftpayConfig.CHARSET,
                    alizftpayConfig.getAlipayPublicKey(), AlizftpayConfig.SIGNTYPE);
        }
    }

    /** 封装支付宝接口调用函数 **/
    private <T extends AlipayResponse> T alipayExecute(AlizftpayConfig alizftpayConfig, AlipayRequest<T> request) throws AlipayApiException {

        if("cert".equals(alizftpayConfig.getEncryptionType())){ //证书加密方式
            return getAlipayClient(alizftpayConfig).certificateExecute(request);

        }else{ //key 或者 空都为默认普通加密方式
            return getAlipayClient(alizftpayConfig).execute(request);
        }
    }



}
